<template>
  <div class="excel-viewer" :class="isZooming && 'is-zooming'">
    <OUpload v-if="local" :onBeforeUpload="beforeUploadSign" accept=".xlsx,.xls" :modelValue="[]">
      <OButton>选择文件</OButton>
    </OUpload>
    <!-- 错误和加载状态显示保持不变 -->
    <div v-if="error" class="error-message">{{ error }}</div>
    <div v-else-if="loading" class="loading-message">加载 Excel 文件中...</div>
    <div v-else-if="sheets.length === 0" class="no-data-message">没有可展示的数据</div>

    <!-- 主要内容区域 -->
    <div v-else class="excel-content">
      <div class="sheet-tabs">
        <OTab v-model="activeSheet" :line="false">
          <OTabPane v-for="(sheet, index) in sheets" :key="index" :value="index" :label="sheet._name"></OTabPane>
        </OTab>
      </div>
      <div class="zoom-wrapper" @click="toggleZoom">
        <div class="zoom-content">
          <OIcon>
            <IconZoomOut v-if="!isZooming"></IconZoomOut>
            <IconZoomIn v-if="isZooming"></IconZoomIn>
          </OIcon>
        </div>

      </div>
      <div class="sheet-container">
        <table v-if="activeSheetData.length">
          <template v-for="(row, rowIndex) in activeSheetData" :key="rowIndex">
            <tr v-if="shouldRenderRow(row)">
              <template v-for="(cell, colIndex) in row" :key="colIndex">
                <td
                  :rowspan="cell.rowspan || 1"
                  :colspan="cell.colspan || 1"
                  :class="{
                    'header-cell': cell.isHeader,
                  }"
                  :style="!cell.styles"
                >
                  <div class="td-cell" v-html="cell.value || '&nbsp;'">
                  </div>
                </td>
              </template>
            </tr>
          </template>
        </table>
      </div>
    </div>
  </div>
  <ODialog
    v-if="!isZooming"
    main-class="zoom-dialog"
    v-model:visible="zoomVisible"
    @close="toggleZoom"
    hideClose
    phoneHalfFull>
    <ExcelViewer :file="file" :currentSheet="activeSheet" isZooming @zoomIn="toggleZoom" />
  </ODialog>
</template>

<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import { OButton, ODialog, OIcon, OTab, OTabPane, OUpload, useMessage } from '@opensig/opendesign';
import IconZoomOut from '~icons/app/icon-zoom-out.svg';
import IconZoomIn from '~icons/app/icon-zoom-in.svg';
import ExcelJS from 'exceljs';


const props = defineProps({
  file: {
    type: [String, File],
    required: true,
  },
  currentSheet: {
    type: [String, Number],
    default: 0,
  },
  isZooming: {
    type: Boolean,
    default: false,
  },
  autoLoad: {
    type: Boolean,
    default: true,
  },
  headerRows: {
    type: Number,
    default: 1,
  },
  sheet: {
    type: String,
    default: null,
  },
  hideEmptyCells: {
    type: Boolean,
    default: false,
  },
  local: {// 调试属性，从本地获取excel
    type: Boolean,
    default: false,
  },
});

const loading = ref(false);
const error = ref(null);
const sheets = ref([]);
const activeSheet = ref(props.currentSheet);

const message = useMessage();
const beforeUploadSign = async (file) => {
  // 校验是否为Excel文件
  if (!['.xlsx', '.xls'].some(type => file.name.endsWith(type))) {
    message.danger({
      content: '请选择Excel文件',
    });
  }
  loadExcel(URL.createObjectURL(file.file));
  return false;
};

const activeSheetData = computed(() => {
  if (sheets.value.length === 0) return [];
  return sheets.value[activeSheet.value]?.rows || [];
});

// 判断是否应该渲染行
const shouldRenderRow = (row) => {
  return row.some((cell) => !props.hideEmptyCells || (cell && !cell.isEmpty));
};

const themeColors = {
  0: '#FFFFFF', // 白色 √
  1: '#000000', // 黑色 √
  2: '#C9CDD1', // 灰色 √
  3: '#4874CB', // 蓝色 √
  4: '#D9E1F4', // 浅蓝 √
  5: '#F9CBAA', // 橙色 √
  6: '#F2BA02', // 浅橙 √
  7: '#00FF00', // 浅绿 √
  8: '#30C0B4', // 青色 √
  9: '#E54C5E', // 红色 √
  10: '#FFC7CE', // 浅红
  11: '#7030A0', // 紫色
};


const hexToRgb = (hex) => {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16),
  } : null;
};

const convertHexToRgba = (hex, alpha) => {
  const rgb = hexToRgb(hex);
  return `rgba(${ rgb.r }, ${ rgb.g }, ${ rgb.b }, ${ alpha })`;
};

// 获取单元格颜色
const getCellColor = (cell) => {
  if (cell.fill && cell.fill.fgColor) {
    if (cell.fill.fgColor.argb) {
      return `#${ cell.fill.fgColor.argb.substring(2) }`; // ARGB 转 RGB
    }
    if (cell.fill.fgColor.theme !== undefined) {
      return convertHexToRgba(themeColors[cell.fill.fgColor.theme] || '#FFFFFF', cell.fill.fgColor.tint || 1); // 主题色转换
    }
  }

  return ''; // 无颜色
};

// 获取单元格字体颜色
const getCellFontColor = (cell) => {
  if (cell.font && cell.font.color && cell.font.color.argb) {
    return `#${ cell.font.color.argb.substring(2) }`; // ARGB 转 RGB
  }
  if (cell.font && cell.font.color && cell.font.color.theme) {
    return themeColors[cell.font.color.theme] || '#000'; // 主题色转换
  }

  return '#000'; // 默认黑色
};
const handleStyles = (cell) => {
  let styles = [];

  // 读取字体颜色
  styles.push(`color: ${ getCellFontColor(cell) }`);
  // 读取背景色
  styles.push(`background-color: ${ getCellColor(cell) }`);

  // 加粗
  if (cell.font && cell.font.bold) {
    styles.push('font-weight: bold');
  }

  // 文字对齐
  if (cell.alignment) {
    if (cell.alignment.horizontal) {
      styles.push(`text-align: ${ cell.alignment.horizontal }`);
    }
    if (cell.alignment.vertical) {
      styles.push(`vertical-align: ${ cell.alignment.vertical }`);
    }
  }

  return styles.join('; ');
};

// 处理合并单元格内容
const handleValue = (value) => {
  if (value && typeof value === 'object' && value.richText) {
    const valueArr = value.richText.reduce((acc, curr) => {
      let colorValue = '';
      if (curr.font && curr.font.color && curr.font.color.argb) {
        colorValue = `#${ curr.font.color.argb.substring(2) }`;
      } else {
        colorValue = `#000`;
      }

      const newData = curr.text
        .split(/\r/)
        .map((item) => `<p style="color:${ colorValue }">${ item }</p>`);
      return acc.concat(newData);
    }, []);

    return valueArr.join('').replace(/\n/g, '<br />');
  }

  return value ? value : '';
};

// 处理常规单元格内容
const handleValueSimple = (value) => {
  if (value && typeof value === 'object' && value.richText) {
    const valueStr = value.richText.reduce((acc, curr) => {
      let colorValue = '';
      if (curr.font && curr.font.color && curr.font.color.theme) {
        colorValue = getCellFontColor(curr) || `#000`;
      }
      if (curr.font && curr.font.color && curr.font.color.argb) {
        colorValue = `#${ curr.font.color.argb.substring(2) }`;
      } else {
        colorValue = `#000`;
      }

      return acc + `<span style="color:inherit">${ curr.text }</span>`;
    }, '');

    return valueStr;
  }

  return value ? value : '';
};
const loadExcel = async (fileUrl) => {
  try {
    loading.value = true;
    error.value = null;
    sheets.value = [];

    const workbook = new ExcelJS.Workbook();
    let arrayBuffer;

    if (fileUrl) {
      const response = await fetch(fileUrl);
      if (!response.ok) throw new Error('文件下载失败');
      arrayBuffer = await response.arrayBuffer();
    } else if (props.file instanceof File) {
      arrayBuffer = await props.file.arrayBuffer();
    } else if (typeof props.file === 'string') {
      const response = await fetch(props.file);
      if (!response.ok) throw new Error('文件下载失败');
      arrayBuffer = await response.arrayBuffer();
    } else {
      throw new Error('不支持的文件类型');
    }
    await workbook.xlsx.load(arrayBuffer);
    workbook.eachSheet((worksheet, sheetId) => {
      const merges = worksheet?.model?.merges || [];
      const rows = [];
      const mergeRows = merges.join(';').match(/\d+/g);
      const maxRow = Math.max(...mergeRows.map(t => parseInt(t, 10)));
      worksheet?.model?.rows?.filter(row => row?.cells.some(cell => {
        return !!cell.value || parseInt(cell.address.slice(1)) <= maxRow;
      }))?.forEach((row, rowIndex) => {
        const cells = [];
        row?.cells?.forEach((cell, colIndex) => {
          // 处理合并单元格
          let rowspan = 1;
          let colspan = 1;
          let isMerged = false;
          for (let merge of merges) {
            const [start, end] = merge.split(':');
            const startCell = worksheet.getCell(start);
            const endCell = worksheet.getCell(end);
            const startRow = startCell.row, startCol = startCell.col;
            const endRow = endCell.row, endCol = endCell.col;

            if (startRow === (rowIndex + 1) && startCol === (colIndex + 1)) {
              rowspan = endRow - startRow + 1;
              colspan = endCol - startCol + 1;
              isMerged = true;

              cells.push({
                rowspan,
                colspan,
                styles: handleStyles(cell.style),
                value: handleValue(startCell.value),
                origin: cell,
              });
              break;
            }
            if (
              rowIndex + 1 >= startRow &&
              rowIndex + 1 <= endRow &&
              colIndex + 1 >= startCol &&
              colIndex + 1 <= endCol
            ) {
              isMerged = true;
              break;
            }
          }
          if (!isMerged) {
            cells.push({
              rowspan,
              colspan,
              styles: handleStyles(cell.style),
              value: handleValueSimple(cell.value || ''),
              origin: cell,
            });
          }
        });
        rows.push(cells);
      });
      const headerRows = Math.max(...(rows?.[0] || []).map(cell => cell.rowspan || 0), 1);

      sheets.value.push({
        ...worksheet,
        rows: rows.map((cells, rowIndex) => {
          return cells.map(cell => {
            return {
              ...cell,
              isHeader: rowIndex + 1 <= headerRows,
            };
          });
        }),
      });
    });
  } catch (err) {
    error.value = `加载 Excel 文件失败: ${ err.message }`;
  } finally {
    loading.value = false;
  }
};

onMounted(() => {
  if (props.autoLoad && props.file) {
    loadExcel();
  }
});

watch(
  () => props.file,
  () => {
    loadExcel();
  },
);


watch(
  () => props.sheet,
  (newVal) => {
    if (newVal && sheets.value.length > 0) {
      const targetIndex = sheets.value.findIndex((s) => s.name === newVal);
      if (targetIndex >= 0) {
        activeSheet.value = targetIndex;
      }
    }
  },
);

// -------------------- 切换放大 --------------------
const emits = defineEmits(['zoomIn', 'zoomOut']);
const zoomVisible = ref(false);

const toggleZoom = () => {
  if (props.isZooming) {
    emits('zoomIn');
  } else {
    zoomVisible.value = !zoomVisible.value;
    emits(zoomVisible.value ? 'zoomOut' : 'zoomIn');
  }
};

</script>

<style scoped lang="scss">
/* 外层容器 */
.excel-viewer {
  width: 100%;
  height: 100%;
  max-width: 100%;
  margin-top: 18px;

  .excel-content {
    height: 100%;
  }

  &.is-zooming {
    margin-top: 0;

    .sheet-tabs {
      display: none;
    }

    .sheet-container {
      margin-top: 0;
    }
  }

  /* Sheet 标签容器 */
  .sheet-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
  }

  .zoom-wrapper {
    height: 0;
    position: relative;
    top: 8px;
    right: 8px;
    z-index: 2;
    float: right;

    .zoom-content {
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      width: 32px;
      height: 32px;
      background-color: rgba(var(--o-black), .4);
      border-radius: 4px;
    }

    .o-icon {
      font-size: 24px;
      color: #fff;
    }

    svg, img {
      padding: 0;
      max-width: 100%;
    }
  }

  /* 表格容器 */
  .sheet-container {
    width: 100%;
    height: 100%;
    overflow: auto;
    border: 1px solid var(--o-color-control4);
    border-radius: 4px;
    margin-top: 16px;
    position: relative;


    table {
      //table-layout: fixed;
      width: auto;
      min-width: 100%; /* 最小宽度为100% */
      border-collapse: collapse;
      position: relative;
      white-space: nowrap; /* 防止单元格内容换行 */

      /* 表头样式增强 */
      .header-cell {
        background-color: var(--o-color-control3-light);
        font-weight: 500;
        position: sticky;
        top: 0;
      }

      tr {
        background-color: transparent !important;
        border: none !important;

        td,
        th {
          //border: none !important;
          border: 1px solid var(--o-color-control4) !important;
          text-align: left;
          padding: 8px 12px !important;
          min-width: 88px;
          min-height: 24px;
          width: fit-content;
          max-width: 320px;

          &:first-child {
            border-left: none !important;
          }

          &:last-child {
            //border-right: none !important;
          }

          .td-cell {
            // TODO
            width: 296px;
            white-space: pre-wrap; /* 防止单元格内容换行 */
          }
        }
      }
    }
  }
}

/* 响应式调整 */
@media (max-width: 768px) {
  .sheet-tabs {
    gap: 6px;
  }
  .sheet-tabs button {
    padding: 6px 12px;
    font-size: 13px;
  }
  th,
  td {
    padding: 6px 8px;
    font-size: 14px;
  }
}
</style>
<style lang="scss">
.zoom-dialog {
  --dlg-edge-gap: 12px;
}
</style>